import datetime
import json
import math
import random
import re

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from py2neo import Graph

from blueapps.account.decorators import login_exempt
from course.models import Member
from .api.get_openid import verify_weixin_code
from .api.verify_account import identify_user
from .account.login_state import encode_state, decode_state
from .models import Question, ErrorQuestion, User_log, Temporary_completion
from .tool.recomment import split_question, get_wmd_distance, wf


@login_exempt
def is_bind_wxuser(request):
    """
    功能：检查该微信用户是否绑定
    输入：request头中带有code
    返回：成功: result: True; data: state + user_id
         失败: result: False; data: state
    失败要求用户认证
    """
    code = request.GET.get('code')

    try:
        # 通过code换取openid与session_key
        session_key, openid = verify_weixin_code(code)
        # 获取登录态
        state = encode_state(session_key=session_key, openid=openid)
    except Exception as e:
        data = {
            'result': False,
            'message': e,
            'code': 500,
        }
        return JsonResponse(data)

    user = Member.objects.filter(openid=openid)
    if user.exists():
        user_id = user.values()[0].get('id')
        data = {
            'result': True,
            'message': '已认证',
            'code': 200,
            'data': {
                'state': state,
                'user_id': user_id,
            }
        }

        return JsonResponse(data)
    else:
        data = {
            'result': False,
            'message': '未认证',
            'code': 401,
            'data': {
                'state': state
            }
        }
        return JsonResponse(data)


@login_exempt
@csrf_exempt
def verify_schooluser(request):
    """
    功能：通过学分制的账号密码, 进行验证, 并绑定用户
    输入：request头中带有username,password,state
    返回：登录态过期：result: False; data: state
         认证成功： result: True; data: state, user_id
         认证失败： result: False; data: state
    """
    if request.method == 'POST':
        username = request.POST.get("name")
        password = request.POST.get("password")
        state = request.META.get("HTTP_COOKIE")

        try:
            # 解码登录态，并判断登录态是否到期
            result, data = decode_state(state)
            if not result:
                data = {
                    'result': False,
                    'message': '登录过期',
                    'code': 401,  # 用户未认证
                    'data': {
                        'state': state
                    }
                }
                return JsonResponse(data)

            openid, session_key = data[0], data[1]

            # 验证学分制账号与密码
            code, user_info = identify_user(username=username, password=password)
        except Exception as e:
            data = {
                'result': False,
                'message': e,
                'code': 500,  # 后端出错
                'data': {
                    'state': state,
                }
            }
            return JsonResponse(data)

        if code is 1:
            user = Member.objects.filter(openid=openid)
            if user.exists():
                user_id = user.values()[0].get('id')
                user.update(
                    class_number=user_info['user_name'],
                    name=user_info['user_real_name'],
                    professional_class=user_info['user_class'],
                    gender=user_info['user_sex'] == '男' and Member.Gender.MAN or Member.Gender.WOMAN,
                    identity=Member.Identity.STUDENT,
                    college=user_info['user_college']
                )
            else:
                user = Member.objects.create(
                    username=username + 'X',
                    openid=openid,
                    class_number=user_info['user_name'],
                    name=user_info['user_real_name'],
                    professional_class=user_info['user_class'],
                    gender=user_info['user_sex'] == '男' and Member.Gender.MAN or Member.Gender.WOMAN,
                    identity=Member.Identity.STUDENT,
                    college=user_info['user_college']
                )
                user_id = user.id
            data = {
                'result': True,
                'message': '认证成功',
                'code': 201,
                'data': {
                    'state': state,
                    'user_id': user_id,
                }
            }

            return JsonResponse(data)
        else:
            if code is 2:
                data = {
                    'result': False,
                    'message': '密码错误',
                    'data': {
                        'state': state,
                    }
                }
                return JsonResponse(data)
            else:
                if code is 3:
                    data = {
                        'result': False,
                        'message': '用户名不存在',
                        'data': {
                            'state': state,
                        }
                    }
                    return JsonResponse(data)


@login_exempt
@csrf_exempt
def get_questions(request):
    """
    功能：返回题目
    输入：用户id
         flag：'1' 返回选择题
               '2' 返回填空题
    """
    user_id = request.GET.get('user_id')
    flag = request.GET.get('flag')
    num = 2

    questions = []
    ids = []

    try:
        if flag == '1':
            all = Question.objects.filter(type=Question.CHOICE).values()
            length = len(all)
            for i in range(0, num):
                question = {}
                index = int(random.random() * length)
                ids.append(all[index].get('id'))
                question['title'] = all[index].get('title')
                options = [all[index].get(j) for j in ['optionA', 'optionB', 'optionC', 'optionD']]
                question['options'] = [
                    {'code': 'A', 'option': options[0]},
                    {'code': 'B', 'option': options[1]},
                    {'code': 'C', 'option': options[2]},
                    {'code': 'D', 'option': options[3]},
                ]
                questions.append(question)
        else:
            all = Question.objects.filter(type=Question.COMPLETION).values()
            length = len(all)
            for i in range(0, num):
                question = {}
                index = int(random.random() * length)
                ids.append(all[index].get('id'))
                question['title'] = all[index].get('title')
                questions.append(question)
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)

    print(ids)
    data = {
        'result': True,
        'code': 200,
        'data': {
            'user_id': user_id,
            'titles': questions,
            'cids': ids,
        }
    }

    return JsonResponse(data)


@login_exempt
def judge_question(request):
    """
    功能：判断用户做的选择题
    输入：用户id、题目id、用户的选项
    """
    # 从请求头中得到
    user_id = request.GET.get('user_id')
    ids = json.loads(request.GET.get('cids'))
    choices = json.loads(request.GET.get('selects'))

    length = len(ids)
    wrong_number = 0

    questions = []
    try:
        for i in range(0, length):
            question = {}
            # q = Coption.objects.filter(cid=cids[i])
            q = Question.objects.filter(id=ids[i])

            question['title'] = q.values()[0].get('title')

            options = [q.values()[0].get(s) for s in ['optionA', 'optionB', 'optionC', 'optionD']]
            question['options'] = [
                {'code': 'A', 'option': options[0]},
                {'code': 'B', 'option': options[1]},
                {'code': 'C', 'option': options[2]},
                {'code': 'D', 'option': options[3]}
            ]
            # options.append([q.values()[0].get(s) for s in ['coA', 'coB', 'coC', 'coD']])
            # a = CoptionAnswer.objects.filter(cid=cids[i]).values()[0].get('answer')
            a = q.values()[0].get('answer')
            question['answer'] = a
            question['selects'] = choices[i]
            if choices[i] == a:
                question['T_or_F'] = True
                # ErrorQuestion.objects.create(user_id=user_id, question_id=ids[i], result=True)
            else:
                wrong_number = wrong_number + 1
                question['T_or_F'] = False
                # 记录用户id与错题的cid
                # ErrorQuestion.objects.create(user_id=user_id, question_id=ids[i], result=False)
            error_q = ErrorQuestion.objects.filter(user_id=user_id, question_id=ids[i])
            if error_q.exists():
                error_q.update(user_id=user_id, question_id=ids[i], result=question['T_or_F'])
            else:
                ErrorQuestion.objects.create(user_id=user_id, question_id=ids[i], result=question['T_or_F'])

            questions.append(question)

        # 记录用户的正确题数与错误题数，以及做题时间
        # 如果今天有log，则在其基础上增加对错题的数目
        # 如果没有log，则进行添加
        log = User_log.objects.filter(time__startswith=str(datetime.datetime.now())[0:10])
        if log.exists():
            log.update(
                right_number=log.values()[0].get('right_number') + (length - wrong_number),
                wrong_number=log.values()[0].get('wrong_number') + wrong_number,
                # time=str(timezone.now()),
                time=timezone.now()
            )
        else:
            User_log.objects.create(
                user_id=user_id,
                right_number=length - wrong_number,
                wrong_number=wrong_number,
                # time=str(timezone.now())
                time=str(timezone.now())
            )

    except Exception as e:
        data = {
            'result': False,
            'message': str(e),
        }

        return JsonResponse(data)

    data = {
        'result': True,
        'data': {
            'titles': questions,
        }
    }

    return JsonResponse(data)


@login_exempt
def storage_completion(request):
    """
    功能: 存储学生做填空题的情况, 待老师批改
    输入: user_id 请求头的填空题id 与 请求头的学生答题内容
    """
    questions_ids = json.loads(request.GET.get('cids'))
    answer = json.loads(request.GET.get('answers'))
    user_id = request.GET.get('user_id')

    try:
        for i in range(0, len(questions_ids)):
            tem_q = Temporary_completion.objects.filter(user_id=user_id, question_id=questions_ids[i])
            if tem_q.exists():
                tem_q.update(
                    user_id=user_id,
                    question_id=questions_ids[i],
                    stu_answer=answer[i]
                )
            else:
                Temporary_completion.objects.create(
                    user_id=user_id,
                    question_id=questions_ids[i],
                    stu_answer=answer[i]
                )
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)
    data = {
        'result': True,
        'code': 200,
        'message': "存储成功",
        'data': {}
    }
    return JsonResponse(data)


@login_exempt
def recommend(request):
    """
    功能：给用户推荐题目
    输入：flag: '1' 根据错题推荐
               '2' 根据用户的所有错题综合推荐
    """
    flag = request.GET.get('flag')
    if flag == '1':
        id = [request.GET.get('cids')]
        question_number = 5
        loop_number = len(id)
    elif flag is '2':
        user_id = request.GET.get('user_id')
        error_cid = ErrorQuestion.objects.filter(user_id=user_id)
        loop_number = error_cid.count()

        # 如果该用户没有错题，则无法根据错题推荐
        if loop_number is 0:
            data = {
                'result': False,
                'data': {
                    'message': '你还没有错题呢'
                }
            }
            return JsonResponse(data)

        id = [i.get('question_id') for i in error_cid.values()]
        question_number = 2

    dict = 'D:/11\weixin\static\dict.txt'
    all_questions = 'D:/11\weixin\static/all_questions.txt'
    questions = []
    ids = []
    try:
        for i in range(0, loop_number):
            ccontent = Question.objects.get(id=id[i]).title
            split_allquestions_words = wf(dict=dict, all_question_file=all_questions)
            distance = get_wmd_distance(split_allquestions_words)
            split_question_words = split_question(question=ccontent)
            WMD_similarity_list = distance[split_question_words][0:question_number]

            for j in WMD_similarity_list:
                question = {}
                recommend_id = str(j[0] + 1)
                q = Question.objects.filter(id=recommend_id)

                question['title'] = q.values()[0].get('title')

                options = [q.values()[0].get(s) for s in ['optionA', 'optionB', 'optionC', 'optionD']]
                question['options'] = [
                    {'code': 'A', 'option': options[0]},
                    {'code': 'B', 'option': options[1]},
                    {'code': 'C', 'option': options[2]},
                    {'code': 'D', 'option': options[3]}
                ]
                questions.append(question)
                ids.append(recommend_id)
                # questions.append({recommend_cid: q.values()[0].get('ccontent')})
                # options.append([q.values()[0].get(i) for i in ['coA', 'coB', 'coC', 'coD']])
    except Exception as e:
        # print(e)
        data = {
            'result': False,
            'data': {
                'message': str(e)
            }
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'data': {
            'titles': questions,
            'cids': ids,
        }
    }

    return JsonResponse(data)


@login_exempt
def recommend_wrong(request):
    """
    功能：返回用户的错题
    输入：用户的id
    """
    user_id = request.GET.get('user_id')

    try:
        eqs = ErrorQuestion.objects.filter(user_id=user_id, result=False).values()

        questions = []
        for q in eqs:
            id = q.get('question_id')
            question = {}
            q = Question.objects.filter(id=id)

            question['title'] = q.values()[0].get('title')

            if q.values()[0].get('type') == Question.CHOICE:
                options = [q.values()[0].get(s) for s in ['optionA', 'optionB', 'optionC', 'optionD']]
                question['options'] = [
                    {'code': 'A', 'option': options[0]},
                    {'code': 'B', 'option': options[1]},
                    {'code': 'C', 'option': options[2]},
                    {'code': 'D', 'option': options[3]}
                ]
                # 选择题 1
                question['flag'] = 1
            else:
                # 填空题 0
                question['flag'] = 0

            a = q.values()[0].get('answer')
            question['answer'] = a
            questions.append(question)
    except Exception as e:
        data = {
            'result': False,
            'data': {
                'message': e
            }
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'data': {
            'titles': questions,
        }
    }

    return JsonResponse(data)


@login_exempt
def set_question(request):
    """
    功能：教师出题，存储数据库
    输入：flag：1 选择题   2 填空题
        knowledge_point: 知识点
        title: 题目
        options: 选项（填空题options为空'）
        answer: 答案
    """
    flag = request.GET.get('flag')
    title = request.GET.get('title')
    answer = request.GET.get('answer')
    knowledge_point = request.GET.get('knowledge')
    num = 1

    try:
        if flag == '2':
            # options = json.loads(request.GET.get('options'))
            optionA = request.GET.get('optionA')
            optionB = request.GET.get('optionB')
            optionC = request.GET.get('optionC')
            optionD = request.GET.get('optionD')

            for i in range(0, num):
                Question.objects.create(
                    type=Question.CHOICE,
                    title=title,
                    knowledge_point=knowledge_point,
                    optionA=optionA,
                    optionB=optionB,
                    optionC=optionC,
                    optionD=optionD,
                    answer=answer,
                )
        else:
            for i in range(0, num):
                Question.objects.create(
                    type=Question.COMPLETION,
                    title=title,
                    knowledge_point=knowledge_point,
                    answer=answer,
                )
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'code': 200,
        'message': '存储成功',
        'data': {}
    }
    return JsonResponse(data)


@login_exempt
def teacher_check(request):
    """
    功能: 统计那些题错的多、统计学生的做错率
    输入: flag 1=统计错题，2=统计做错率
         if flag == 1 : num想看错的最多的前num个题
    """
    flag = request.GET.get('flag')
    # all = ErrorQuestion.objects.all().values()
    all = ErrorQuestion.objects.filter(result=0).values()

    if flag == '1':
        q_ids = list(set([i.get('question_id') for i in all]))
        record = {}
        try:
            for i in q_ids:
                record[i] = ErrorQuestion.objects.filter(question_id=i).count()

            record = sorted(record.items(), key=lambda x: x[1],
                            reverse=True)  # [('99', 2), ('123', 1), ('126', 1), ('98', 1)]

            questions = []
            # 获取信息
            for i in record:
                question = {}
                # 题目信息
                q = Question.objects.filter(id=i[0])
                question['title'] = q.values()[0].get('title')
                options = [q.values()[0].get(s) for s in ['optionA', 'optionB', 'optionC', 'optionD']]
                question['options'] = [
                    {'code': 'A', 'option': options[0]},
                    {'code': 'B', 'option': options[1]},
                    {'code': 'C', 'option': options[2]},
                    {'code': 'D', 'option': options[3]}
                ]
                question['answer'] = q.values()[0].get('answer')
                # 选择题1  填空题0
                question['flag'] = q.values()[0].get('type') == Question.CHOICE and '1' or '0'

                # 获取答错题同学的信息
                u_id = [i.get('user_id') for i in ErrorQuestion.objects.filter(question_id=i[0], result=False).values()]
                users_info = []
                for j in u_id:
                    u = {}
                    user = Member.objects.get(id=j)
                    u['name'] = user.name
                    u['professional_class'] = user.professional_class
                    users_info.append(u)

                question['user_info'] = users_info
                questions.append(question)
        except Exception as e:
            data = {
                'result': False,
                'code': 500,
                'message': str(e),
                'data': {}
            }
            return JsonResponse(data)

        data = {
            'result': True,
            'code': 200,
            'data': {
                'titles': questions,
            }
        }

        return JsonResponse(data)

    else:
        try:
            u_ids = list(set([i.get('user_id') for i in all]))

            user_info = []
            for i in u_ids:
                info = {}
                right_num = ErrorQuestion.objects.filter(user_id=i, result=True).count()
                wrong_num = ErrorQuestion.objects.filter(user_id=i, result=False).count()
                # right_rate = (right_num == 0 and float(("%0.4f" % (right_num / (right_num + wrong_num)))) or 0)
                right_rate = right_num != 0 and str((right_num / (right_num + wrong_num)) * 100)[: 5] or '0'
                # right_rate = str(rate * 100)[: 5]
                # wrong_rate = ("%0.4f" % wrong_num / (right_num + wrong_num))
                user = Member.objects.get(id=i)
                info['user_id'] = i
                info['user_name'] = user.name
                info['class_number'] = user.class_number
                info['right_rate'] = right_rate + '%'
                user_info.append(info)
        except Exception as e:
            data = {
                'result': False,
                'code': 500,
                'message': str(e),
                'data': {}
            }
            return JsonResponse(data)

        print(user_info)
        data = {
            'result': True,
            'code': 200,
            'data': user_info,
        }
        return JsonResponse(data)


@login_exempt
def teacher_grade(request):
    """
    功能: 老师给同学答的填空题批改, 给老师返回数据
    返回: 填空题的题目、答案、学生的作答
    """
    try:
        all = Temporary_completion.objects.all().values()
        questions = []
        ids = []
        user_ids = []
        for i in all:
            question = {}
            q = Question.objects.get(id=i.get('question_id'))
            question['correct_answer'] = q.answer
            question['title'] = q.title
            question['answer'] = i.get('stu_answer')
            user = Member.objects.get(id=i.get('user_id'))
            question['username'] = user.name
            question['class_number'] = user.class_number
            questions.append(question)
            ids.append(q.id)
            user_ids.append(user.id)
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'code': 200,
        'data': {
            'titles': questions,
            'ids': ids,
            'user_ids': user_ids
        }
    }

    return JsonResponse(data)


@login_exempt
def teacher_grade_record(request):
    """
    功能: 将老师给填空题判断的存储
    输入: 请求头中的user_id question_id T_or_F
    """
    user_id = json.loads(request.GET.get('user_ids'))
    # question_ids = request.GET.get('cids')
    # user_ids = request.GET.get('answers')

    # user_ids = json.loads(request.GET.get('user_ids'))
    questions_ids = json.loads(request.GET.get('ids'))
    T_or_F = json.loads(request.GET.get('correct'))

    try:
        for i in range(0, len(user_id)):
            ErrorQuestion.objects.create(
                user_id=user_id[i],
                question_id=questions_ids[i],
                result=T_or_F[i],
            )
            Temporary_completion.objects.filter(
                user_id=user_id[i],
                question_id=questions_ids[i],
            ).delete()

        log = User_log.objects.filter(user_id=user_id, time__startswith=str(datetime.datetime.now())[0:10])
        right_number = sum(T_or_F)
        wrong_number = len(T_or_F) - right_number
        if log.exists():
            log.update(
                right_number=log.values()[0].get('right_number') + right_number,
                wrong_number=log.values()[0].get('wrong_number') + wrong_number,
                # time=str(timezone.now()),
                time=timezone.now()
            )
        else:
            User_log.objects.create(
                user_id=user_id,
                right_number=right_number,
                wrong_number=wrong_number,
                # time=str(timezone.now())
                time=str(timezone.now())
            )
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'code': 200,
        'message': "存储成功",
        'data': {}
    }

    return JsonResponse(data)


@login_exempt
def graph(request):
    """
    功能：返回学生每天做题的数量与正确率
    输入：学生的id
    """
    user_id = request.GET.get('user_id')

    now = datetime.datetime.now()

    date = []
    total = []
    right_rate = []

    try:
        for i in range(0, 7):
            time = str(now - datetime.timedelta(days=i))[0:10]
            time_split = time.split('-')
            date.append(time_split[1] + '.' + time_split[2])

            log = User_log.objects.filter(user_id=user_id, time__startswith=time)
            if log.exists():
                log = log.values()[0]
                right_number = log.get('right_number')
                wrong_number = log.get('wrong_number')
                total.append(right_number + wrong_number)
                right_rate.append(right_number == 0 and 0 or
                                  float(str(right_number / (right_number + wrong_number))[0:4]))
            else:
                total.append(0)
                right_rate.append(0)
    except Exception as e:
        data = {
            'result': False,
            'code': 500,
            'message': str(e),
            'data': {}
        }
        return JsonResponse(data)

    data = {
        'result': True,
        'code': 200,
        'data': {
            'date': date,
            'total': total,
            'right_rate': right_rate,
        }
    }
    return JsonResponse(data)


@login_exempt
def knowledge_group(request):
    """
    1. 得到错误知识点
    2. 得到与错误知识点的节点有四种关系的的节点，记录节点名字和其与错误知识点的关系
    """
    id = request.GET.get("cid")
    print(id)
    nodes = []
    str_nodes = []

    '''提取图谱信息'''
    graph = Graph('http://localhost:7474', user='neo4j', password='123456')
    konwledge_point = Question.objects.get(id=id).knowledge_point
    nodes.append(konwledge_point)
    relations = ['包含', '并列', '因果', '前驱']

    node = graph.nodes.match('概念', name=konwledge_point).first()

    for r in relations:
        res = graph.match({node, }, r_type=r)
        for i in res:
            if i.end_node.get('name') not in nodes:
                nodes.append(i.end_node.get('name'))
            if i.start_node.get('name') not in nodes:
                nodes.append(i.start_node.get('name'))
            str_nodes.append(re.findall('\w+', str(i)))

    '''构造图谱'''
    r_x = 0
    r_y = 0
    xx = -800
    yy = r_y
    print(nodes)
    print(str_nodes)

    num = len(nodes) - 1
    data = [
        {
            'name': nodes[0],
            'x': r_x,
            'y': r_y,
        },
        {
            'name': nodes[1],
            'x': xx,
            'y': yy,
        }
    ]
    nodes = nodes[2:]
    angle = (2 * math.pi) / num

    for i in nodes:
        xx, yy = (xx - r_x) * math.cos(angle) - (yy - r_y) * math.sin(angle) + r_x, (yy - r_y) * math.cos(angle) + (xx -
                  r_x) * math.sin(angle) + r_y

        data.append({
            'name': i,
            'x': int(xx),
            'y': int(yy),
        })

    print(data)

    links = []
    for rel in str_nodes:
        relation = {
            'source': rel[0],
            'target': rel[2],
            'label': {
                'normal': {
                    'show': 'true',
                    'formatter': rel[1],
                    'fontSize': 8,
                }
            }
        }
        links.append(relation)

    print(links)

    return JsonResponse(
        {
            'data': data,
            'links': links,
        }
    )
